// 
// File:   prism_scanner.h
// Author: cionescu
//
// Created on 8 January 2007, 10:10
//

#ifndef _prism_scanner_H
#define	_prism_scanner_H
#include <spirit/symbols/symbols.hpp>
#include <boost/spirit/utility/distinct.hpp>
#include <spirit/utility/chset.hpp>
#include <spirit/utility/confix.hpp>
#include <spirit/actor.hpp>
#include <spirit/actor/assign_actor.hpp>
#include <spirit/actor/insert_key_actor.hpp>
#include <spirit/core.hpp>

#include "prism_actions.h"
#include "prism_tokens.h"

using namespace boost::spirit;
using namespace std;

void print_string( char const * b, char const * e) {
    string s(b,e);
    clog<<"string detected "<<s<<endl;
}

void print_int( int i) {
    clog<<"int detected "<<i<<endl;
}

void print_letter(const char* const l) {
    clog<<"letter detected:"<<*l<<endl;
}

template <typename T>
struct prism_ureal_parser_policies : public ureal_parser_policies<T>
{
    static const bool expect_dot = true;
    static const bool allow_leading_dot = false;
    static const bool allow_trailing_dot = false;
    
};

real_parser<double, prism_ureal_parser_policies<double> > prism_real_p;
/**
Tokenizer class for the prism parser.
Implemented using the spirit framework.
*/
template<typename DataT>
struct prism_scanner : public grammar<prism_scanner<DataT> > {
    DataT& m_data;
    prism_scanner(DataT& d): m_data(d), m_key_a(d), m_op_a(d), m_ident_a(d), m_const_a(d){};
    keyword_action<DataT,keyword_token> m_key_a;
    keyword_action<DataT,op_token> m_op_a;
    keyword_action<DataT,ident_token> m_ident_a;
    keyword_action<DataT,const_token> m_const_a;
    
    template <typename ScannerT>
    struct definition {
        definition(prism_scanner const& self) {
            language= * ( skip
                        | keyword[self.m_key_a]
                        | identifier[self.m_ident_a]
                        | constant[self.m_const_a]
                        | op[self.m_op_a]
                        );
            
            keyword = lexeme_d [
                    keywords
                    >> (eps_p - (alnum_p | '_')) 
            ];
            
            identifier = lexeme_d[
                        ((  (alpha_p| '_') 
                        >> *(alnum_p| '_')
                        ) - keyword )
            ];
            
            skip = lexeme_d [
                    space_p  
            ];
            
            constant = lexeme_d[
                        prism_real_p |
                         (uint_p >> (eps_p - (alnum_p | '_')))
                         
            ];
            
            op = lexeme_d[
                        ( str_p("<=")
                        | str_p("..")
                        | str_p(">=")
                        | str_p("->")
                        | str_p("!=")
                        | chset_p("!&*()+={[}]:;<>/|-'"))
            ];
            
            keywords =  "module", "endmodule", "init",
                        "bool", "int", "double", "const", 
                        "true", "false", "dtmc", "ctmc", "mdp"
            ;
            
            BOOST_SPIRIT_DEBUG_NODE(skip);
            BOOST_SPIRIT_DEBUG_NODE(keywords);
            BOOST_SPIRIT_DEBUG_NODE(op);
            BOOST_SPIRIT_DEBUG_NODE(constant);
            BOOST_SPIRIT_DEBUG_NODE(identifier);
            BOOST_SPIRIT_DEBUG_NODE(language);            
        };
        
        symbols<>               keywords;
        
        rule<ScannerT>          language, keyword, op,
                                identifier, constant, skip;
        
        rule<ScannerT> const&
        start() const { return language; };
        
    };
};

#endif	/* _prism_scanner_H */

